home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / MISC / JFSOCKET.ZIP / JFSOCKET.TXT
Encoding:
Text File  |  1996-03-16  |  13.4 KB  |  374 lines

  1.  
  2.                      BSD SOCKETS: A QUICK AND DIRTY PRIMER
  3.                                        
  4.    Jim Frost
  5.    Software Tool & Die
  6.    Copyright (c) 1988, 1994 Jim Frost
  7.    All Rights Reserved
  8.    Last changed November 4, 1994
  9.    
  10.    
  11.    
  12.      _________________________________________________________________
  13.    
  14. Table Of Contents
  15.  
  16.      * Introduction
  17.      * The Analogy (or: What is a socket, anyway?)
  18.      * Installing Your New Phone (or: How to listen for socket
  19.        connections)
  20.      * Dialing (or: How to call a socket)
  21.      * Conversation (or: How to talk between sockets)
  22.      * Hanging Up (or: What to do when you're done with a socket)
  23.      * Speaking The Language (or: Byte-order is important)
  24.      * The Future Is In Your Hands (or: What to do now)
  25.        
  26.    
  27.    
  28.    
  29.      _________________________________________________________________
  30.    
  31. Introduction 
  32.  
  33.    
  34.    
  35.    As you delve into the mysteries of UNIX, you find more and more things
  36.    that are difficult to understand immediately. One of these things, at
  37.    least for most people, is the BSD socket concept. This is a short
  38.    tutorial that explains what they are, how they work, and gives sample
  39.    code showing how to use them.
  40.    
  41. The Analogy (or: What is a socket, anyway?) 
  42.  
  43.    
  44.    
  45.    The socket is the BSD method for accomplishing interprocess
  46.    communication (IPC). What this means is a socket is used to allow one
  47.    process to speak to another, very much like the telephone is used to
  48.    allow one person to speak to another.
  49.    
  50.    The telephone analogy is a very good one, and will be used repeatedly
  51.    to describe socket behavior.
  52.    
  53. Installing Your New Phone (or: How to listen for socket connections) 
  54.  
  55.    
  56.    
  57.    In order for a person to receive telephone calls, he must first have a
  58.    telephone installed. Likewise you must create a socket to listen for
  59.    connections. This process involves several steps. First you must make
  60.    a new socket, which is similar to having a telephone line installed.
  61.    The socket() command is used to do this.
  62.    
  63.    Since sockets can have several types, you must specify what type of
  64.    socket you want when you create one. One option that you have is the
  65.    addressing format of a socket. Just as the mail service uses a
  66.    different scheme to deliver mail than the telephone company uses to
  67.    complete calls, so can sockets differ. The two most common addressing
  68.    schemes are AF_UNIX and IAF_INET. AF_UNIX addressing uses UNIX
  69.    pathnames to identify sockets; these sockets are very useful for IPC
  70.    between processes on the same machine. AF_INET addressing uses
  71.    Internet addresses which are four-byte numbers usually written as four
  72.    decimal numbers separated by periods (such as 192.9.200.10). In
  73.    addition to the machine address, there is also a port number which
  74.    allows more than one AF_INET socket on each machine. AF_INET addresses
  75.    are what we will deal with here, as they are the most useful and
  76.    widely used.
  77.    
  78.    Another option which you must supply when creating a socket is the
  79.    type of socket. The two most common types are SOCK_STREAM and
  80.    SOCK_DGRAM. SOCK_STREAM indicates that data will come across the
  81.    socket as a stream of characters, while SOCK_DGRAM indicates that data
  82.    will come in bunches (called datagrams). We will be dealing with
  83.    SOCK_STREAM sockets, which are the most common and easiest to use.
  84.    
  85.    After creating a socket, we must give the socket an address to listen
  86.    to, just as you get a telephone number so that you can receive calls.
  87.    The bind() function is used to do this (it binds a socket to an
  88.    address, hence the name).
  89.    
  90.    SOCK_STREAM type sockets have the ability to queue incoming connection
  91.    requests, which is a lot like having "call waiting" for your
  92.    telephone. If you are busy handling a connection, the connection
  93.    request will wait until you can deal with it. The listen() function is
  94.    used to set the maximum number of requests (up to a maximum of five,
  95.    usually) that will be queued before requests start being denied. While
  96.    it is not necessary to use the listen() function, it's good practice.
  97.    
  98.    The following function shows how to use the socket(), bind(), and
  99.    listen() functions to establish a socket which can accept calls:
  100.    
  101.  
  102. /* code to establish a socket; originally from bzs@bu-cs.bu.edu
  103.  */
  104.  
  105. int establish(unsigned short portnum)
  106. { char   myname[MAXHOSTNAME+1];
  107.   int    s;
  108.   struct sockaddr_in sa;
  109.   struct hostent *hp;
  110.  
  111.   memset(&sa, 0, sizeof(struct sockaddr_in)); /* clear our address */
  112.   gethostname(myname, MAXHOSTNAME);           /* who are we? */
  113.   hp= gethostbyname(myname);                  /* get our address info */
  114.   if (hp == NULL)                             /* we don't exist !? */
  115.     return(-1);
  116.   sa.sin_family= hp->h_addrtype;              /* this is our host address */
  117.   sa.sin_port= htons(portnum);                /* this is our port number */
  118.   if ((s= socket(AF_INET, SOCK_STREAM, 0)) < 0) /* create socket */
  119.     return(-1);
  120.   if (bind(s,&sa,sizeof(struct sockaddr_in)) < 0) {
  121.     close(s);
  122.     return(-1);                               /* bind address to socket */
  123.   }
  124.   listen(s, 3);                               /* max # of queued connects */
  125.   return(s);
  126. }
  127.  
  128.    
  129.    
  130.    After you create a socket to get calls, you must wait for calls to
  131.    that socket. The accept() function is used to do this. Calling
  132.    accept() is analogous to picking up the telephone if it's ringing.
  133.    Accept() returns a new socket which is connected to the caller.
  134.    
  135.    The following function can be used to accept a connection on a socket
  136.    that has been created using the establish() function above:
  137.    
  138.  
  139. /* wait for a connection to occur on a socket created with establish()
  140.  */
  141. int get_connection(int s)
  142. { int t;                  /* socket of connection */
  143.  
  144.   if ((t = accept(s,NULL,NULL)) < 0)   /* accept connection if there is one */
  145.     return(-1);
  146.   return(t);
  147. }
  148.  
  149.    
  150.    
  151.    Unlike with the telephone, you may still accept calls while processing
  152.    previous connections. For this reason you usually fork off jobs to
  153.    handle each connection. The following code shows how to use
  154.    establish() and get_connection() to allow multiple connections to be
  155.    dealt with:
  156.    
  157.  
  158. #include <errno.h>       /* obligatory includes */
  159. #include <signal.h>
  160. #include <stdio.h>
  161. #include <unistd.h>
  162. #include <sys/types.h>
  163. #include <sys/socket.h>
  164. #include <sys/wait.h>
  165. #include <netinet/in.h>
  166. #include <netdb.h>
  167.  
  168. #define PORTNUM 50000 /* random port number, we need something */
  169.  
  170. void fireman(void);
  171. void do_something(int);
  172.  
  173. main()
  174. { int s, t;
  175.  
  176.   if ((s= establish(PORTNUM)) < 0) {  /* plug in the phone */
  177.     perror("establish");
  178.     exit(1);
  179.   }
  180.  
  181.   signal(SIGCHLD, fireman);           /* this eliminates zombies */
  182.  
  183.   for (;;) {                          /* loop for phone calls */
  184.     if ((t= get_connection(s)) < 0) { /* get a connection */
  185.       if (errno == EINTR)             /* EINTR might happen on accept(), */
  186.         continue;                     /* try again */
  187.       perror("accept");               /* bad */
  188.       exit(1);
  189.     }
  190.     switch(fork()) {                  /* try to handle connection */
  191.     case -1 :                         /* bad news.  scream and die */
  192.       perror("fork");
  193.       close(s);
  194.       close(t);
  195.       exit(1);
  196.     case 0 :                          /* we're the child, do something */
  197.       close(s);
  198.       do_something(t);
  199.       exit(0);
  200.     default :                         /* we're the parent so look for */
  201.       close(t);                       /* another connection */
  202.       continue;
  203.     }
  204.   }
  205. }
  206.  
  207. /* as children die we should get catch their returns or else we get
  208.  * zombies, A Bad Thing.  fireman() catches falling children.
  209.  */
  210. void fireman(void)
  211. {
  212.   while (waitpid(-1, NULL, WNOHANG) > 0)
  213.     ;
  214. }
  215.  
  216. /* this is the function that plays with the socket.  it will be called
  217.  * after getting a connection.
  218.  */
  219. void do_something(int s)
  220. {
  221.   /* do your thing with the socket here
  222.       :
  223.       :
  224.    */
  225. }
  226.  
  227. Dialing (or: How to call a socket) 
  228.  
  229.    
  230.    
  231.    You now know how to create a socket that will accept incoming calls.
  232.    So how do you call it? As with the telephone, you must first have the
  233.    phone before using it to call. You use the socket() function to do
  234.    this, exactly as you establish a socket to listen to.
  235.    
  236.    After getting a socket to make the call with, and giving it an
  237.    address, you use the connect() function to try to connect to a
  238.    listening socket. The following function calls a particular port
  239.    number on a particular host:
  240.    
  241.  
  242. int call_socket(char *hostname, unsigned short portnum)
  243. { struct sockaddr_in sa;
  244.   struct hostent     *hp;
  245.   int a, s;
  246.  
  247.   if ((hp= gethostbyname(hostname)) == NULL) { /* do we know the host's */
  248.     errno= ECONNREFUSED;                       /* address? */
  249.     return(-1);                                /* no */
  250.   }
  251.  
  252.   memset(&sa,0,sizeof(sa));
  253.   memcpy((char *)&sa.sin_addr,hp->h_addr,hp->h_length); /* set address */
  254.   sa.sin_family= hp->h_addrtype;
  255.   sa.sin_port= htons((u_short)portnum);
  256.  
  257.   if ((s= socket(hp->h_addrtype,SOCK_STREAM,0)) < 0)   /* get socket */
  258.     return(-1);
  259.   if (connect(s,&sa,sizeof sa) < 0) {                  /* connect */
  260.     close(s);
  261.     return(-1);
  262.   }
  263.   return(s);
  264. }
  265.  
  266.    
  267.    
  268.    This function returns a connected socket through which data can flow.
  269.    
  270. Conversation (or: How to talk between sockets) 
  271.  
  272.    
  273.    
  274.    Now that you have a connection between sockets you want to send data
  275.    between them. The read() and write() functions are used to do this,
  276.    just as they are for normal files. There is only one major difference
  277.    between socket reading and writing and file reading and writing: you
  278.    don't usually get back the same number of characters that you asked
  279.    for, so you must loop until you have read the number of characters
  280.    that you want. A simple function to read a given number of characters
  281.    into a buffer is:
  282.    
  283.  
  284. int read_data(int s,     /* connected socket */
  285.               char *buf, /* pointer to the buffer */
  286.               int n      /* number of characters (bytes) we want */
  287.              )
  288. { int bcount; /* counts bytes read */
  289.   int br;     /* bytes read this pass */
  290.  
  291.   bcount= 0;
  292.   br= 0;
  293.   while (bcount < n) {             /* loop until full buffer */
  294.     if ((br= read(s,buf,n-bcount)) > 0) {
  295.       bcount += br;                /* increment byte counter */
  296.       buf += br;                   /* move buffer ptr for next read */
  297.     }
  298.     else if (br < 0)               /* signal an error to the caller */
  299.       return(-1);
  300.   }
  301.   return(bcount);
  302. }
  303.  
  304.    
  305.    
  306.    A very similar function should be used to write data; we leave that
  307.    function as an exercise to the reader.
  308.    
  309. Hanging Up (or: What to do when you're done with a socket) 
  310.  
  311.    
  312.    
  313.    Just as you hang up when you're through speaking to someone over the
  314.    telephone, so must you close a connection between sockets. The normal
  315.    close() function is used to close each end of a socket connection. If
  316.    one end of a socket is closed and the other tries to write to its end,
  317.    the write will return an error.
  318.    
  319. Speaking The Language (or: Byte order is important) 
  320.  
  321.    
  322.    
  323.    Now that you can talk between machines, you have to be careful what
  324.    you say. Many machines use differing dialects, such as ASCII versus
  325.    (yech) EBCDIC. More commonly there are byte-order problems. Unless you
  326.    always pass text, you'll run up against the byte-order problem.
  327.    Luckily people have already figured out what to do about it.
  328.    
  329.    Once upon a time in the dark ages someone decided which byte order was
  330.    "right". Now there exist functions that convert one to the other if
  331.    necessary. Some of these functions are htons() (host to network short
  332.    integer), ntohs() (network to host short integer), htonl() (host to
  333.    network long integer), and ntohl() (network to host long integer).
  334.    Before sending an integer through a socket, you should first massage
  335.    it with the htonl() function:
  336.    
  337.  
  338. i= htonl(i);
  339. write_data(s, &i, sizeof(i));
  340.  
  341.    
  342.    
  343.    and after reading data you should convert it back with ntohl():
  344.    
  345.  
  346. read_data(s, &i, sizeof(i));
  347. i= ntohl(i);
  348.  
  349.    
  350.    
  351.    If you keep in the habit of using these functions you'll be less
  352.    likely to goof it up in those circumstances where it is necessary.
  353.    
  354. The Future Is In Your Hands (or: What to do now) 
  355.  
  356.    
  357.    
  358.    Using just what's been discussed here, you should be able to build
  359.    your own programs that communicate with sockets. As with all new
  360.    things, however, it would be a good idea to look at what's already
  361.    been done. While there are not a lot of books describing BSD sockets,
  362.    one good reference is Unix Network Programming by W. Richard Stevens
  363.    (Prentice-Hall 1990, ISBN 0-13-949876-1). In addition, you should look
  364.    at some of the many public-domain applications which make use of
  365.    sockets, since real applications are the best teachers. One such
  366.    application is available by anonymous ftp from ftp.std.com in
  367.    /src/network/msend.1.2.tar.gz.
  368.    
  369.    Beware that the examples given here leave out a lot of error checking
  370.    which should be used in a real application. You should check the
  371.    manual pages for each of the functions discussed here for further
  372.    information. If you have specific questions regarding sockets, please
  373.    feel free to ask me at email address jimf@world.std.com.
  374.